package com.platform.qujia.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.platform.qujia.config.BasicInfo;
import com.platform.qujia.constantEnum.DecimalConstant;
import com.platform.qujia.constantEnum.PayWayPayTypeEnum;
import com.platform.qujia.constantEnum.TianQuetechPayEnum;
import com.platform.qujia.dao.CommodityMapper;
import com.platform.qujia.dao.NonOilOrderMapper;
import com.platform.qujia.dao.OrderDetailsMapper;
import com.platform.qujia.dao.PayWayMapper;
import com.platform.qujia.enums.CardRecordType;
import com.platform.qujia.enums.PayWayServiceChargeEnum;
import com.platform.qujia.enums.PayWayUseTypeEnum;
import com.platform.qujia.param.request.TradeReverseScanPayParameter;
import com.platform.qujia.param.request.YunHuaPayParam;
import com.platform.qujia.param.request.YunHuaPayPayParams;
import com.platform.qujia.param.response.YunhuaPayRes;
import com.platform.qujia.param.response.YunhuaResponse;
import com.platform.qujia.pay.PayChannelHandler;
import com.platform.qujia.pay.PaymentStrategy;
import com.platform.qujia.pay.strategy.YunhuaChannel;
import com.platform.qujia.pojo.*;
import com.platform.qujia.pojo.dto.DualNonOilOrderPayDto;
import com.platform.qujia.pojo.dto.DualNonOilOrderPayListDto;
import com.platform.qujia.pojo.dto.ScanOrderDTO;
import com.platform.qujia.pojo.nonOil.Commodity;
import com.platform.qujia.pojo.nonOil.NonOilOrder;
import com.platform.qujia.pojo.nonOil.OrderDetails;
import com.platform.qujia.service.DualNonOilOrderCreateService;
import com.platform.qujia.service.DualNonOilOrderPayService;
import com.platform.qujia.service.EnterpriseService;
import com.platform.qujia.utils.*;
import com.platform.qujia.utils.exception.CustomException;
import com.yunhua.oil.common.core.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


@Service("dualNonOilOrderPayService")
@Slf4j
public class DualNonOilOrderPayServiceImpl implements DualNonOilOrderPayService {

    @Autowired
    private PayChannelHandler payChannelHandler;

    @Resource
    private PayWayMapper payWayMapper;

    @Autowired
    private CommodityMapper commodityMapper;

    @Autowired
    private OrderDetailsMapper orderDetailsMapper;

    @Autowired
    private EnterpriseService enterpriseService;

    @Autowired
    private NonOilOrderMapper nonOilOrderMapper;

    @Autowired
    private DualNonOilOrderCreateService dualNonOilOrderCreateService;

    private DateTimeFormatter timestampFormatter;

    @Value("${domain.payName}${server.servlet.context-path}/getNonOilOrderCallback")
    private String sxfSpjNotifyUrl;

    private String publicKey;
    @Value("${spring.profiles.active}")
    public void setProfile(String profile){
        if (org.apache.commons.lang3.StringUtils.contains(profile,"prod")) {
            publicKey = SXFPaySign.sxfPublic;
        }else{
            publicKey = SXFPaySign.sxfTestPublic;
        }
    }

    @PostConstruct
    public void postCons(){
        timestampFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
    }


    @Override
    public ScanOrderDTO dualScanPay(NonOilOrder nonOilOrder) {
        log.info("双屏机非油订单B扫C开始支付：[{}]",JSONObject.toJSONString(nonOilOrder));

        PayWay payWayForm=new PayWay();
        payWayForm.setUseType(PayWayUseTypeEnum.CONSUME.getValue().toString());             //使用类型
        payWayForm.setStationId(nonOilOrder.getStationId().intValue());
        payWayForm.setAppType(PayWayServiceChargeEnum.APPTYPE_POS.getValue().toString());
        PayWay payWay = payWayMapper.getOneStationPayWay(payWayForm); //获取该油站的支付类型，默认找pos的

        if (payWay == null || payWay.getServiceCharge() == null) {
            log.error("找不到支付渠道，stationId:{}, 请求参数:{}",nonOilOrder.getStationId(),nonOilOrder);
            throw new CustomException("找不到支付渠道");
        }

        PayWayPayTypeEnum payTypeEnum = PayWayPayTypeEnum.getByValue(Integer.valueOf(payWay.getPayType()));
        PaymentStrategy strategy = payChannelHandler.getPaymentStrategy(payTypeEnum);


        // 调随行付
        try{
            Object preParam = null;
            if (payTypeEnum == PayWayPayTypeEnum.Pay_Type_Accompanying_payment) {
                TradeReverseScanPayParameter param=new TradeReverseScanPayParameter();
                param.setOrgId(BasicInfo.TRADE_REVERSE_PAY_ORGID);
                param.setReqId(UUID.fastUUID().toString(true));
                param.setTimestamp(timestampFormatter.format(LocalDateTime.now()));
                param.setMno(payWay.getMno());
                param.setOrdNo(nonOilOrder.getOrderCode());
                param.setAuthCode(nonOilOrder.getAuthCode());
                param.setAmt(nonOilOrder.getActuallyAmount().toString());
                param.setSubject("双屏机非油订单消费");
                param.setTrmIp(nonOilOrder.getTrmIp());
//                param.setExtend(CardRecordType.POS_RECHARGE.getKey()+","+preRecordId);  // 随行付扩展字段 用于回调，可以不要
//                param.setExtend(String.format("{\"payType\":\"%s\",\"pId\":%d}", CardRecordType.POS_RECHARGE.getKey(),preRecordId));
                param.setNotifyUrl(sxfSpjNotifyUrl);
                preParam = param;
            }
            log.info("双屏机非油订单消费调用第三方支付，渠道：{}",payTypeEnum.getKey());
            // 进行第三方支付调用
            Object result = strategy.doPay(null,null,payWay,preParam);

            // 检查调用是否成功
            TianQuetechPayEnum payEnum = strategy.checkResult3(null, result);
            log.info("双屏机非油订单消费调用第三方支付成功，渠道：{}，status:{}",payTypeEnum.getKey(),payEnum);

            ScanOrderDTO scanOrder = new ScanOrderDTO();
            scanOrder.setOrderNo(nonOilOrder.getOrderCode());
            scanOrder.setStatus(payEnum);
            if (payEnum == TianQuetechPayEnum.PAY_SUCCESS) {
                // 免密同步返回成功，随行付不会回调上送地址，需手动回调
                if (payTypeEnum == PayWayPayTypeEnum.Pay_Type_Accompanying_payment) {
                    DualNonOilOrderPayServiceImpl bean = SpringUtils.getBean(DualNonOilOrderPayServiceImpl.class);
                    bean.asyncSpjCallback((TradeReversePayInfo) result);
                }
            }
            return scanOrder;
        }catch (Exception e){
            log.info("调用第三方支付失败，渠道：{}，ex:{}",payTypeEnum.getKey(),e.getMessage());
            // 商品库存回滚
//            callBackCommodity(nonOilOrder.getOrderCode());

            if(e instanceof CustomException){
                throw e;
            }else{
                log.error(e.getMessage(),e);
                throw new CustomException("支付失败");
            }
        }
    }

    @Async
    public void asyncSpjCallback(TradeReversePayInfo info){
        dualNonOilOrderCreateService.orderCallback(info.getOrdNo());
    }

//    private void callBackCommodity(String orderCode){
//        synchronized (this) {
//            List<OrderDetails> orderDetails = orderDetailsMapper.selectByOrderCode(orderCode);
//            for (OrderDetails orderDetail : orderDetails) {
//                Commodity commodity = commodityMapper.selectByPrimaryKey(orderDetail.getCommodityId());
//                Commodity com = new Commodity();
//                com.setCommodityId(commodity.getCommodityId());
//                com.setInventory(commodity.getInventory() + orderDetail.getCommodityNum());
//                commodityMapper.updateByPrimaryKeySelective(com);
//            }
//        }
//    }

    @Override
    @Transactional
    public NonOilOrder createOrder(DualNonOilOrderPayListDto dualNonOilOrderPayListDto) {
        PayWay payWayForm=new PayWay();
        payWayForm.setUseType(PayWayUseTypeEnum.CONSUME.getValue().toString());             //使用类型
        payWayForm.setStationId(dualNonOilOrderPayListDto.getStationId());
        payWayForm.setAppType(PayWayServiceChargeEnum.APPTYPE_POS.getValue().toString());
        PayWay payWay = payWayMapper.getOneStationPayWay(payWayForm); //获取该油站的支付类型，默认找pos的

        if (payWay == null || payWay.getServiceCharge() == null) {
            log.error("找不到支付渠道，stationId:{}, 请求参数:{}",dualNonOilOrderPayListDto.getStationId(),dualNonOilOrderPayListDto);
            throw new CustomException("找不到支付渠道");
        }
        Station station = enterpriseService.selectStationById(dualNonOilOrderPayListDto.getStationId());
        // 生成订单号
        String orderNo= StringUtils.generateOrdNo();
        NonOilOrder nonOilOrder = new NonOilOrder();

        // 订单金额
        BigDecimal payableAmount = BigDecimal.ZERO;

        for (DualNonOilOrderPayDto dualNonOilOrderPayDto : dualNonOilOrderPayListDto.getDualNonOilOrderPayDtoList()) {
            Commodity req = new Commodity();
            req.setCommodityCode(dualNonOilOrderPayDto.getCommodityCode());
            req.setStationId(dualNonOilOrderPayListDto.getStationId().longValue());
            Commodity commodity = commodityMapper.selectByCommodityCode(req);
            if(Objects.isNull(commodity)){
                throw new CustomException("商品不存在");
            }
            if(dualNonOilOrderPayDto.getNum() <= 0){
                throw new CustomException("商品数量不正确");
            }

            if(commodity.getInventory() <= 0 || (commodity.getInventory() - dualNonOilOrderPayDto.getNum()) < 0){
                throw new CustomException("商品数量没有库存");
            }

//                // 扣减商品库存
//                req.setInventory(commodity.getInventory() - dualNonOilOrderPayDto.getNum());
//                req.setCommodityId(commodity.getCommodityId());
//                int i = commodityMapper.updateByPrimaryKeySelective(req);
//                if(i <= 0){
//                    throw new CustomException("扣减库存失败");
//                }

            // 生成订单详情
            BigDecimal price = createOrderDetails(commodity, dualNonOilOrderPayDto.getNum(), orderNo,dualNonOilOrderPayDto.getTotalPrice());
            payableAmount = payableAmount.add(price);
        }

        // 创建订单
        nonOilOrder.setOrderCode(orderNo);
        nonOilOrder.setStationId(station.getStationId().longValue());
        nonOilOrder.setStationName(station.getStationName());
        nonOilOrder.setEnterpriseId(station.getEnterpriseId().longValue());
        nonOilOrder.setEnterpriseName(station.getEnterpriseName());
        nonOilOrder.setCustomerId(dualNonOilOrderPayListDto.getCustomerId());
        nonOilOrder.setStaffId(dualNonOilOrderPayListDto.getStaffId());
        nonOilOrder.setDeviceId(dualNonOilOrderPayListDto.getDeviceId());
        nonOilOrder.setCreateTime(new Date());
        nonOilOrder.setPayType("spj"); // 双屏机
        nonOilOrder.setStatus("0");
        nonOilOrder.setPayableAmount(payableAmount);
        nonOilOrder.setActuallyAmount(payableAmount);
        nonOilOrder.setDiscountAmount(BigDecimal.ZERO);
        // 计算实收
        calculatorChannelFee(nonOilOrder,payWay,payableAmount);

        nonOilOrderMapper.insertSelective(nonOilOrder);

        log.info("双屏机非油订单B扫C开始支付 创建订单：[{}]",JSONObject.toJSONString(nonOilOrder));
        return nonOilOrder;
    }

    public BigDecimal createOrderDetails(Commodity commodity, Long num, String orderNo, BigDecimal oldTotalPrice){

        BigDecimal totalPrice = commodity.getSalePrice().multiply(new BigDecimal(num));
        if(oldTotalPrice.compareTo(totalPrice) != 0){
            throw new CustomException("商品价格过期");
        }
        OrderDetails orderDetails = new OrderDetails();
        orderDetails.setOrderCode(orderNo);
        orderDetails.setCommodityId(commodity.getCommodityId());
        orderDetails.setCommodityName(commodity.getCommodityName());
        orderDetails.setCommodityCode(commodity.getCommodityCode());
        orderDetails.setCategoryId(commodity.getCategoryId());
        orderDetails.setCategoryName(commodity.getCommodityName());
        orderDetails.setCommodityNum(num);
        orderDetails.setSalePrice(commodity.getSalePrice());
        orderDetails.setTotalPrice(totalPrice);
        orderDetailsMapper.insertSelective(orderDetails);
        return totalPrice;
    }


    private void calculatorChannelFee(NonOilOrder nonOilOrder, PayWay payWay, BigDecimal payableAmount){

        nonOilOrder.setChannelFeePayer(payWay.getChannelFeePayer());
        nonOilOrder.setServiceCharge(payWay.getServiceCharge());

        // 渠道费
        if(payableAmount.compareTo(DecimalConstant.O_01)<=0){
            nonOilOrder.setCommission(BigDecimal.ZERO);
            return;
        }
        if (StringUtils.equals("1",nonOilOrder.getChannelFeePayer())) {
            // 油企承担
            //渠道费
            BigDecimal commission = payableAmount.multiply(payWay.getServiceCharge()).multiply(DecimalConstant.O_001).setScale(2, RoundingMode.HALF_UP);
            nonOilOrder.setCommission(commission);
        }else{
            // 司机承担
            // 司机承担的渠道费
            BigDecimal driverCommission = payableAmount.multiply(payWay.getServiceCharge()).multiply(DecimalConstant.O_001).setScale(2, RoundingMode.HALF_UP);
            nonOilOrder.setCommission(driverCommission);
            payableAmount = payableAmount.add(driverCommission).setScale(2,RoundingMode.HALF_UP);
            nonOilOrder.setActuallyAmount(payableAmount);
        }
    }

    @Override
    public ResultData callbackSpj(Map<String, Object> request) {
        log.info("=====双屏机B扫C创建非油订单随行付回调--参数:{}",request);
        String sign = (String) request.remove("sign");
        String signContent = RSASignature.getOrderContent(request);
        if (!RSASignature.doCheck(signContent, sign, this.publicKey)) {
            log.info("=====双屏机B扫C创建非油订单随行付回调验签失败--参数:{}",request);
            return ResultData.error("回调验签失败");
        }
        String ordNo = String.valueOf(request.get("ordNo"));
        if (org.apache.commons.lang3.StringUtils.isBlank(ordNo)) {
            log.info("=====订单号为空");
            return ResultData.error("回调验签失败");
        }
        dualNonOilOrderCreateService.orderCallback(ordNo);
        return ResultData.success("回调验签成功");
    }

    @Override
    @Transactional
    public NonOilOrder createOrderCash(DualNonOilOrderPayListDto dualNonOilOrderPayListDto) {
        Station station = enterpriseService.selectStationById(dualNonOilOrderPayListDto.getStationId());
        // 生成订单号
        String orderNo= StringUtils.generateOrdNo();
        NonOilOrder nonOilOrder = new NonOilOrder();
        synchronized (this){

            // 订单金额
            BigDecimal payableAmount = BigDecimal.ZERO;

            for (DualNonOilOrderPayDto dualNonOilOrderPayDto : dualNonOilOrderPayListDto.getDualNonOilOrderPayDtoList()) {
                Commodity req = new Commodity();
                req.setCommodityCode(dualNonOilOrderPayDto.getCommodityCode());
                req.setStationId(dualNonOilOrderPayListDto.getStationId().longValue());
                Commodity commodity = commodityMapper.selectByCommodityCode(req);
                if(Objects.isNull(commodity)){
                    throw new CustomException("商品不存在");
                }
                if(dualNonOilOrderPayDto.getNum() <= 0){
                    throw new CustomException("商品数量不正确");
                }

                if(commodity.getInventory() <= 0 || (commodity.getInventory() - dualNonOilOrderPayDto.getNum()) < 0){
                    throw new CustomException("商品数量没有库存");
                }

                // 扣减商品库存
                req.setInventory(commodity.getInventory() - dualNonOilOrderPayDto.getNum());
                req.setCommodityId(commodity.getCommodityId());
                int i = commodityMapper.updateByPrimaryKeySelective(req);
                if(i <= 0){
                    throw new CustomException("扣减库存失败");
                }

                // 生成订单详情
                BigDecimal price = createOrderDetails(commodity, dualNonOilOrderPayDto.getNum(), orderNo,dualNonOilOrderPayDto.getTotalPrice());
                payableAmount = payableAmount.add(price);
            }

            // 创建订单
            nonOilOrder.setOrderCode(orderNo);
            nonOilOrder.setStationId(station.getStationId().longValue());
            nonOilOrder.setStationName(station.getStationName());
            nonOilOrder.setEnterpriseId(station.getEnterpriseId().longValue());
            nonOilOrder.setEnterpriseName(station.getEnterpriseName());
            nonOilOrder.setCustomerId(dualNonOilOrderPayListDto.getCustomerId());
            nonOilOrder.setStaffId(dualNonOilOrderPayListDto.getStaffId());
            nonOilOrder.setDeviceId(dualNonOilOrderPayListDto.getDeviceId());
            nonOilOrder.setPayTime(new Date());
            nonOilOrder.setCreateTime(new Date());
            nonOilOrder.setPayType("xj"); // 双屏机现金
            nonOilOrder.setStatus("1"); // 支付成功
            nonOilOrder.setPayableAmount(payableAmount);
            nonOilOrder.setActuallyAmount(payableAmount);
            nonOilOrder.setDiscountAmount(BigDecimal.ZERO);
            nonOilOrder.setServiceCharge(BigDecimal.ZERO);
            nonOilOrder.setCommission(BigDecimal.ZERO);

            nonOilOrderMapper.insertSelective(nonOilOrder);
        }
        log.info("双屏机非油订单B扫C开始支付 创建订单：[{}]");
        return nonOilOrder;
    }

}
